/** * ID3v1Body.java * * This program is distributed under the terms of the GNU General Public * License * Copyright 2008 NJ Pearman * * This file is part of MobScrob. * * MobScrob is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MobScrob is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MobScrob. If not, see <http://www.gnu.org/licenses/>. */ package mobscrob.id3; import java.io.IOException; import mobscrob.logging.Log; import mobscrob.logging.LogFactory; import mobscrob.mp3.MP3Stream; /** * @author Neill * */ public class ID3v1Body extends AbstractID3Body { private static final Log log = LogFactory.getLogger(ID3v1Body.class); protected static final int TRACK_TITLE_LEN = 30; protected static final int ARTIST_LEN = 30; protected static final int ALBUM_TITLE_LEN = 30; protected static final int YEAR_LEN = 4; protected static final int COMMENT_LEN = 29; protected static final int TRACK_NUMBER_LEN = 1; protected static final int GENRE_LEN = 1; private int currFrame; public ID3v1Body(ID3Header header, MP3Stream is) { super(header, is); // set the current frame to the first frame currFrame = ID3v1Frame.TRACK_TITLE; } public boolean readComplete() { return currFrame > ID3v1Frame.GENRE; } /* * (non-Javadoc) * * @see mobscrob.id3.AbstractID3Body#readNextFrame() */ public Frame readNextFrame() throws IOException { final String methodName = "1"; if (currFrame > ID3v1Frame.GENRE) { log.info(methodName, "Finished reading tag"); return null; } Frame frame = null; // read the current frame switch (currFrame) { case ID3v1Frame.TRACK_TITLE: frame = readFrame(ID3v1Frame.ID_TRACK_TITLE, TRACK_TITLE_LEN); break; case ID3v1Frame.ARTIST: frame = readFrame(ID3v1Frame.ID_ARTIST, ARTIST_LEN); break; case ID3v1Frame.ALBUM: frame = readFrame(ID3v1Frame.ID_ALBUM_TITLE, ALBUM_TITLE_LEN); break; case ID3v1Frame.YEAR: frame = readFrame(ID3v1Frame.ID_YEAR, YEAR_LEN); break; case ID3v1Frame.COMMENT: frame = readFrame(ID3v1Frame.ID_COMMENT, COMMENT_LEN); break; case ID3v1Frame.TRACK_NUMBER: frame = readSingleByteAsIntFrame(ID3v1Frame.ID_TRACK_NUMBER); break; case ID3v1Frame.GENRE: frame = readSingleByteAsIntFrame(ID3v1Frame.ID_GENRE); break; default: log.error(methodName, "Unexpected current frame: " + currFrame); } // shift bit for next read currFrame = currFrame << 1; return frame; } private Frame readFrame(String frameID, int frameLen) throws IOException { final String methodName = "2"; byte[] bytes = new byte[frameLen]; int byteCount = is.read(bytes); if (byteCount != frameLen) { throw new IOException("Unable to read tag frame " + frameID + ", num bytes read: " + byteCount); } log.info(methodName, "Read ID3v1 frame: " + new String(bytes)); return new ID3v1Frame(frameID, frameLen, bytes); } private Frame readSingleByteAsIntFrame(String frameID) throws IOException { final String methodName = "3"; byte[] bytes = new byte[1]; int next = is.read(); if (next < 0) { throw new IOException("Unable to read single byte as integer " + frameID + ", end of stream"); } log.info(methodName, "Read ID3v1 frame: " + new String(bytes)); String str = String.valueOf(next); return new ID3v1Frame(frameID, 1, str.getBytes()); } public class ID3v1Frame extends Frame { public static final String ID_ARTIST = "ART"; public static final String ID_TRACK_TITLE = "TRA"; public static final String ID_ALBUM_TITLE = "ALB"; public static final String ID_YEAR = "YEA"; public static final String ID_COMMENT = "COM"; public static final String ID_TRACK_NUMBER = "NUM"; public static final String ID_GENRE = "GEN"; static final int TRACK_TITLE = 2; static final int ARTIST = 4; static final int ALBUM = 8; static final int YEAR = 16; static final int COMMENT = 32; static final int TRACK_NUMBER = 64; static final int GENRE = 128; public ID3v1Frame(String id, int length, byte[] raw) { super(id, length, raw); } public String getContentsAsString() { String s = new String(rawBytes); int i = s.indexOf(0x00); // ignore any empty content if (i > -1) { s = s.substring(0, i); } return s; } } }